package com.example.mytestdemo.car.surfaceview

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.SurfaceHolder
import android.view.SurfaceView
import com.example.mytestdemo.R


/**
 * @author tgw
 * @date 2022/11/23
 * @describe
 */
class TestSurFaceView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
) : SurfaceView(context, attrs, defStyleAttr), SurfaceHolder.Callback {

    companion object {
        private const val TAG = "TestSurFaceView"
    }

    private var paint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private var path: Path
    private var surfaceHolder: SurfaceHolder?

    //绘制笔迹至画布
    private var flag = false

    //SurfaceView的绘制能否放在View.onDraw(canvas)中？
    //不行。SurfaceView在初始化时调用了 setWillNotDraw(true) 表示该控件没有需要绘制的内容，所以
    //在屏幕刷新时，SurfaceView的 onDraw() 方法默认是不会被调用。
    //当然我们也可以，再把它设定false来触发 onDraw() ，不过一般没有这样必要，因为SurfaceView自带
    //了缓冲画布，并不需要 onDraw() 中画布。

    init {
        paint.color = Color.BLUE
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = 5f
        path = Path()

        //初始化获取surfaceHolder
        surfaceHolder = holder
        surfaceHolder?.addCallback(this)

        //默认情况下SurfaceView渲染时会显示黑色的背景，如果当我们需要显示透明的背景可以使用如下的代
        //码。弊端是SurfaceView会显示在Window的顶层，遮住其他的View。
//        surfaceHolder?.setFormat(PixelFormat.TRANSPARENT)
//        setZOrderOnTop(true)
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        Log.d(TAG, "surfaceCreated: ")
        flag = true
//        drawCanvas()
        drawCanvas1()
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
        Log.d(TAG, "surfaceChanged: ")
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        Log.d(TAG, "surfaceDestroyed: ")
        flag = false
    }


    //通过onTouchEvent监听到屏幕上的手势移动，并将轨迹保存在 Path 中。
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {
                path.moveTo(event.x, event.y)
                return true
            }
            MotionEvent.ACTION_MOVE -> {
                path.lineTo(event.x, event.y)
                drawCanvas3()
            }
        }
        return super.onTouchEvent(event)
    }

    //在子线程中将轨迹绘制到画布上
    private fun drawCanvas() {
        Thread {
            while (flag && surfaceHolder != null) {
                val canvas = surfaceHolder?.lockCanvas()
                if (canvas != null) {
                    canvas.drawPath(path, paint)
                    surfaceHolder?.unlockCanvasAndPost(canvas)
                }
            }
        }.start()
    }

    //局部刷新不影响，drawCanvas2绘制的文字刷新
    private fun drawCanvas3() {
        Thread {
            val canvas = surfaceHolder?.lockCanvas(Rect(0, 100, 1000, 500))
            if (canvas != null) {
                canvas.drawPath(path, paint)
                surfaceHolder?.unlockCanvasAndPost(canvas)
            }
        }.start()
    }


    // 屏幕为什么只显示了4个数字？
//这是因为其他的数字绘制在别的画布上，所以没有显示出来。这也证明了，前端缓冲区经过交换后，转
//换为后端缓冲区时，并没有把正显示在屏幕上的缓冲区内容复制下来。
//为什么是0 3 6 9？两个缓冲区的不应该是1 3 5 7 9吗？
//原因很简单，虽然名义上叫双缓冲区但其实并不止两个缓冲区，在这个例子中，实际上有三个缓冲区。
//根据Goodle的官方文档解释，Surface中缓冲区个数是根据需求动态分配的，如果用户获取画布的频率
//较慢，那么将会分配两个缓冲区，否则，将分配3的倍数个缓冲区。总得来说，Surface分配的缓冲画布
//数量会大于等于2，具体多少需要视情况而定
    private fun drawCanvas1() {
        var num = ArrayList<Int>()
        Thread {
//            while (flag && surfaceHolder != null) {
            clearDefaultBg()
            for (i in 0..9) {
//                    val canvas = surfaceHolder?.lockCanvas()

                val canvas = surfaceHolder?.lockCanvas(Rect(0, 0, 1000, 100))
                Log.e(TAG, "drawCanvas: $i")

                //为了正确显示所有数字，将前面的数据缓存起来，后续一次性绘制
                num.add(i)
                if (canvas != null) {
                    canvas?.drawColor(context.resources.getColor(R.color.purple_200))
                    paint.textSize = 60f
                    for (j in num) {
                        canvas?.drawText("$j", j * 50f, 50f, paint)
                    }
                    surfaceHolder?.unlockCanvasAndPost(canvas)
                }
            }
//            }
        }.start()
    }

    //这是因为当我们第一次获取画布时，这块画布还没有被画过，属于脏画布，系统认为它都应该被画上，
    //所以返回了全屏的画布。
    //由于这样的机制存在，实际上我们在获取区域画布时需要判断，是否是我们指定的区域画布，否则就需
    //要先把画布清理一遍，才能获取到我们期望的区域画布。清屏代码如下：
    //
    // 这里实际是画上背景
    private fun clearDefaultBg() {
        //们第一次获取画布时，这块画布还没有被画过，属于脏画布，系统认为它都应该被画上，
        //利用这特性首次绘制一块背景色
        val canvas = surfaceHolder?.lockCanvas(Rect(0, 0, 1, 1))

        if (canvas != null) {
            val rectCanvas = canvas.clipBounds
            Log.e(TAG, "drawCanvas0:${rectCanvas} ")
            Log.e(TAG, "drawCanvas0 height:${rectCanvas.height()}-----$height------ ")
            Log.e(TAG, "drawCanvas0 width:${rectCanvas.width()}-----$width------ ")
            if (rectCanvas.height() == height && rectCanvas.width() == width) {
                canvas.drawColor(Color.RED)
                surfaceHolder?.unlockCanvasAndPost(canvas)
            } else {
                surfaceHolder?.unlockCanvasAndPost(canvas)
            }
        }
    }


    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        surfaceHolder?.removeCallback(this)
    }

// Canvas lockCanvas ()
//获取Surface中Canvas

//Canvas lockCanvas ( Rect dirty)
//获取指定区域的Canvas。一般在需要局部更新时会用到。

//有关“局部更新”下一小节会介绍。
//Canvas lockHardwareCanvas ()
//获取硬件加速的Canvas。

//unlockCanvasAndPost ( Canvas canvas)
//释放Canvas。使用Canvas绘制完成后，必须释放Canvas才会显示在屏幕上

//Surface getSurface ()
//获取Surface对象。

//Rect getSurfaceFrame ()
//获取当前Surface的大小

//boolean isCreating ()
//Surface是否正在创建中

//void setFixedSize (int width, int height)
//将Surface设定为固定大小

//void setFormat (int format)
//设定Surface的像素格式

//void setSizeFromLayout ()
//允许Surface根据容器的布局大小，调整Surface的大小。默认就会被调用。
}